/*
Copyright 2021-2024 New Vector Ltd.

SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details.
 */

import UIKit

@objc protocol SettingsSecureBackupTableViewSectionDelegate: AnyObject {
    // Table view rendering
    func settingsSecureBackupTableViewSectionDidUpdate(_ settingsSecureBackupTableViewSection: SettingsSecureBackupTableViewSection)

    func settingsSecureBackupTableViewSection(_ settingsSecureBackupTableViewSection: SettingsSecureBackupTableViewSection, textCellForRow: Int) -> MXKTableViewCellWithTextView
    func settingsSecureBackupTableViewSection(_ settingsSecureBackupTableViewSection: SettingsSecureBackupTableViewSection, buttonCellForRow: Int) -> MXKTableViewCellWithButton

    // Secure backup
    func settingsSecureBackupTableViewSectionShowSecureBackupReset(_ settingsSecureBackupTableViewSection: SettingsSecureBackupTableViewSection)

    // Key backup
    func settingsSecureBackupTableViewSectionShowKeyBackupCreate(_ settingsSecureBackupTableViewSection: SettingsSecureBackupTableViewSection)
    func settingsSecureBackupTableViewSection(_ settingsSecureBackupTableViewSection: SettingsSecureBackupTableViewSection, showKeyBackupRecover keyBackupVersion: MXKeyBackupVersion)
    func settingsSecureBackupTableViewSection(_ settingsSecureBackupTableViewSection: SettingsSecureBackupTableViewSection, showKeyBackupDeleteConfirm keyBackupVersion: MXKeyBackupVersion)

    // Life cycle
    func settingsSecureBackupTableViewSection(_ settingsSecureBackupTableViewSection: SettingsSecureBackupTableViewSection, showActivityIndicator show: Bool)
    func settingsSecureBackupTableViewSection(_ settingsSecureBackupTableViewSection: SettingsSecureBackupTableViewSection, showError error: Error)
}

private enum BackupRows {
    case info(text: String)
    case createSecureBackupAction
    case resetSecureBackupAction
    case createKeyBackupAction
    case restoreFromKeyBackupAction(keyBackupVersion: MXKeyBackupVersion, title: String)
    case deleteKeyBackupAction(keyBackupVersion: MXKeyBackupVersion)
}

/// SettingsSecureBackupTableViewSection provides UITableViewCells to manage secure backup and key backup.
///
/// All states are described in SettingsSecureBackupViewState.
/// All actions in SettingsSecureBackupViewAction.
@objc final class SettingsSecureBackupTableViewSection: NSObject {

    // MARK: - Properties

    @objc weak var delegate: SettingsSecureBackupTableViewSectionDelegate?

    // MARK: Private

    // This view class holds the model because the model is in pure Swift
    // whereas this class can be used from objC
    private var viewModel: SettingsSecureBackupViewModelType!

    // Need to know the state to make `cellForRow` deliver cells accordingly
    private var viewState: SettingsSecureBackupViewState = .loading {
        didSet {
            self.updateBackupRows()
        }
    }

    private var userDevice: MXDeviceInfo
    
    private var backupRows: [BackupRows] = []

    // MARK: - Public

    @objc init(withRecoveryService recoveryService: MXRecoveryService, keyBackup: MXKeyBackup, userDevice: MXDeviceInfo) {
        self.viewModel = SettingsSecureBackupViewModel(recoveryService: recoveryService, keyBackup: keyBackup)
        self.userDevice = userDevice
        super.init()
        self.viewModel.viewDelegate = self

        self.viewModel.process(viewAction: .load)
    }
    
    @objc func numberOfRows() -> Int {
        return self.backupRows.count
    }
    
    @objc func cellForRow(atRow row: Int) -> UITableViewCell {
        let backupRow = self.backupRows[row]
        
        var cell: UITableViewCell
        switch backupRow {
        case .info(let text):
            cell = self.textCell(atRow: row, text: text)
        case .createSecureBackupAction:
            cell = self.buttonCellForCreateSecureBackup(atRow: row)
        case .resetSecureBackupAction:
            cell = self.buttonCellForResetSecureBackup(atRow: row)
        case .createKeyBackupAction:
            cell = self.buttonCellForCreateKeyBackup(atRow: row)
        case .restoreFromKeyBackupAction(keyBackupVersion: let keyBackupVersion, let title):
            cell = self.buttonCellForRestoreFromKeyBackup(keyBackupVersion: keyBackupVersion, title: title, atRow: row)
        case .deleteKeyBackupAction(keyBackupVersion: let keyBackupVersion):
            cell = self.buttonCellForDeleteKeyBackup(keyBackupVersion: keyBackupVersion, atRow: row)
        }
        
        return cell
    }

    @objc func reload() {
        self.viewModel.process(viewAction: .load)
    }

    @objc func deleteKeyBackup(keyBackupVersion: MXKeyBackupVersion) {
        self.viewModel.process(viewAction: .deleteKeyBackup(keyBackupVersion))
    }

    // MARK: - Data Computing
    
    private func updateBackupRows() {
        
        let backupRows: [BackupRows]
        
        switch self.viewState {
        case .loading:
            backupRows = [
                .info(text: VectorL10n.securitySettingsSecureBackupInfoChecking)
            ]
            
        case .noSecureBackup(let keyBackupState):
            switch keyBackupState {
            case .noKeyBackup:
                let noBackup = VectorL10n.settingsKeyBackupInfoNone
                let signoutWarning = VectorL10n.settingsKeyBackupInfoSignoutWarning
                let infoText = [noBackup, signoutWarning].joined(separator: "\n")
                
                backupRows = [
                    .info(text: infoText),
                    .createSecureBackupAction
                ]
            case .keyBackup(let keyBackupVersion, _, let progress):
                if let progress = progress {
                    backupRows = [
                        .info(text: importProgressText(for: progress)),
                        .deleteKeyBackupAction(keyBackupVersion: keyBackupVersion)
                    ]
                } else {
                    backupRows = [
                        .info(text: VectorL10n.securitySettingsSecureBackupInfoValid),
                        .restoreFromKeyBackupAction(keyBackupVersion: keyBackupVersion, title: VectorL10n.securitySettingsSecureBackupRestore),
                        .deleteKeyBackupAction(keyBackupVersion: keyBackupVersion)
                    ]
                }
            case .keyBackupNotTrusted(let keyBackupVersion, _):
                backupRows = [
                    .info(text: VectorL10n.securitySettingsSecureBackupInfoValid),
                    .restoreFromKeyBackupAction(keyBackupVersion: keyBackupVersion, title: VectorL10n.securitySettingsSecureBackupRestore),
                    .deleteKeyBackupAction(keyBackupVersion: keyBackupVersion)
                ]
            }
        case .secureBackup(let keyBackupState):
            switch keyBackupState {
            case .noKeyBackup:
                let noBackup = VectorL10n.settingsKeyBackupInfoNone
                let signoutWarning = VectorL10n.settingsKeyBackupInfoSignoutWarning
                let infoText = [noBackup, signoutWarning].joined(separator: "\n")
                
                backupRows = [
                    .info(text: infoText),
                    .createKeyBackupAction,
                    .resetSecureBackupAction
                ]
            case .keyBackup(let keyBackupVersion, _, let progress):
                if let progress = progress {
                    backupRows = [
                        .info(text: importProgressText(for: progress)),
                        .deleteKeyBackupAction(keyBackupVersion: keyBackupVersion),
                        .resetSecureBackupAction
                    ]
                } else {
                    backupRows = [
                        .info(text: VectorL10n.securitySettingsSecureBackupInfoValid),
                        .restoreFromKeyBackupAction(keyBackupVersion: keyBackupVersion, title: VectorL10n.securitySettingsSecureBackupRestore),
                        .deleteKeyBackupAction(keyBackupVersion: keyBackupVersion),
                        .resetSecureBackupAction
                    ]
                }
            case .keyBackupNotTrusted(let keyBackupVersion, _):
                backupRows = [
                    .info(text: VectorL10n.securitySettingsSecureBackupInfoValid),
                    .restoreFromKeyBackupAction(keyBackupVersion: keyBackupVersion, title: VectorL10n.securitySettingsSecureBackupRestore),
                    .deleteKeyBackupAction(keyBackupVersion: keyBackupVersion),
                    .resetSecureBackupAction
                ]
            }
        }
        self.backupRows = backupRows
    }
    
    private func importProgressText(for progress: Progress) -> String {
        let percentage = Int(round(progress.fractionCompleted * 100))
        return VectorL10n.keyBackupRecoverFromPrivateKeyInfo + " \(percentage)%"
    }

    // MARK: - Cells -
    
    private func textCell(atRow row: Int, text: String) -> UITableViewCell {
        guard let delegate = self.delegate else {
            return UITableViewCell()
        }
        
        let cell = delegate.settingsSecureBackupTableViewSection(self, textCellForRow: row)
        cell.mxkTextView.text = text
        return cell
    }
    
    // MARK: - Button cells
    
    private func buttonCellForCreateSecureBackup(atRow row: Int) -> UITableViewCell {
        
        guard let delegate = self.delegate else {
            return UITableViewCell()
        }
        
        let cell: MXKTableViewCellWithButton = delegate.settingsSecureBackupTableViewSection(self, buttonCellForRow: row)
        
        let btnTitle = VectorL10n.securitySettingsSecureBackupSetup
        cell.mxkButton.setTitle(btnTitle, for: .normal)
        cell.mxkButton.setTitle(btnTitle, for: .highlighted)
        
        cell.mxkButton.vc_addAction {
            self.viewModel.process(viewAction: .createSecureBackup)
        }
        
        return cell
    }
    
    private func buttonCellForResetSecureBackup(atRow row: Int) -> UITableViewCell {
        
        guard let delegate = self.delegate else {
            return UITableViewCell()
        }
        
        let cell: MXKTableViewCellWithButton = delegate.settingsSecureBackupTableViewSection(self, buttonCellForRow: row)
        
        let btnTitle = VectorL10n.securitySettingsSecureBackupReset
        cell.mxkButton.setTitle(btnTitle, for: .normal)
        cell.mxkButton.setTitle(btnTitle, for: .highlighted)
        cell.mxkButton.tintColor = ThemeService.shared().theme.warningColor
        
        cell.mxkButton.vc_addAction {
            self.viewModel.process(viewAction: .resetSecureBackup)
        }
        
        return cell
    }

    private func buttonCellForCreateKeyBackup(atRow row: Int) -> UITableViewCell {

        guard let delegate = self.delegate else {
            return UITableViewCell()
        }

        let cell: MXKTableViewCellWithButton = delegate.settingsSecureBackupTableViewSection(self, buttonCellForRow: row)

        let btnTitle = VectorL10n.securitySettingsSecureBackupSetup
        cell.mxkButton.setTitle(btnTitle, for: .normal)
        cell.mxkButton.setTitle(btnTitle, for: .highlighted)

        cell.mxkButton.vc_addAction {
            self.viewModel.process(viewAction: .createKeyBackup)
        }

        return cell
    }

    private func buttonCellForRestoreFromKeyBackup(keyBackupVersion: MXKeyBackupVersion, title: String, atRow row: Int) -> UITableViewCell {
        guard let delegate = self.delegate else {
            return UITableViewCell()
        }

        let cell: MXKTableViewCellWithButton = delegate.settingsSecureBackupTableViewSection(self, buttonCellForRow: row)
        cell.mxkButton.setTitle(title, for: .normal)
        cell.mxkButton.setTitle(title, for: .highlighted)
        cell.mxkButton.vc_addAction {
            self.viewModel.process(viewAction: .restoreFromKeyBackup(keyBackupVersion))
        }
        return cell
    }

    private func buttonCellForDeleteKeyBackup(keyBackupVersion: MXKeyBackupVersion, atRow row: Int) -> UITableViewCell {
        guard let delegate = self.delegate else {
            return UITableViewCell()
        }

        let cell: MXKTableViewCellWithButton = delegate.settingsSecureBackupTableViewSection(self, buttonCellForRow: row)
        let btnTitle = VectorL10n.securitySettingsSecureBackupDelete
        cell.mxkButton.setTitle(btnTitle, for: .normal)
        cell.mxkButton.setTitle(btnTitle, for: .highlighted)
        cell.mxkButton.tintColor = ThemeService.shared().theme.warningColor
        cell.mxkButton.vc_addAction {
            self.viewModel.process(viewAction: .confirmDeleteKeyBackup(keyBackupVersion))
        }

        return cell
    }
}


// MARK: - KeyBackupSetupRecoveryKeyViewModelViewDelegate
extension SettingsSecureBackupTableViewSection: SettingsSecureBackupViewModelViewDelegate {
    
    func settingsSecureBackupViewModel(_ viewModel: SettingsSecureBackupViewModelType, didUpdateViewState viewState: SettingsSecureBackupViewState) {
        self.viewState = viewState

        // The tableview datasource will call `self.cellForRow()`
        self.delegate?.settingsSecureBackupTableViewSectionDidUpdate(self)
    }

    func settingsSecureBackupViewModel(_ viewModel: SettingsSecureBackupViewModelType, didUpdateNetworkRequestViewState networkRequestViewSate: SettingsSecureBackupNetworkRequestViewState) {
        switch networkRequestViewSate {
        case .loading:
            self.delegate?.settingsSecureBackupTableViewSection(self, showActivityIndicator: true)
        case .loaded:
            self.delegate?.settingsSecureBackupTableViewSection(self, showActivityIndicator: false)
        case .error(let error):
            self.delegate?.settingsSecureBackupTableViewSection(self, showError: error)
        }
    }
    
    func settingsSecureBackupViewModelShowSecureBackupReset(_ viewModel: SettingsSecureBackupViewModelType) {
        self.delegate?.settingsSecureBackupTableViewSectionShowSecureBackupReset(self)
    }

    func settingsSecureBackupViewModelShowKeyBackupCreate(_ viewModel: SettingsSecureBackupViewModelType) {
        self.delegate?.settingsSecureBackupTableViewSectionShowKeyBackupCreate(self)
    }

    func settingsSecureBackupViewModel(_ viewModel: SettingsSecureBackupViewModelType, showKeyBackupRecover keyBackupVersion: MXKeyBackupVersion) {
        self.delegate?.settingsSecureBackupTableViewSection(self, showKeyBackupRecover: keyBackupVersion)
    }
    
    func settingsSecureBackupViewModel(_ viewModel: SettingsSecureBackupViewModelType, showKeyBackupDeleteConfirm keyBackupVersion: MXKeyBackupVersion) {
        self.delegate?.settingsSecureBackupTableViewSection(self, showKeyBackupDeleteConfirm: keyBackupVersion)
    }
}
